package com.uxsino.watcher.lib.services;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.uxsino.commons.utils.ClassPathResourceWalker;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @ClassName VersionParser
 * @Description TODO
 * @Author <a href="mailto:royrxc@gmail.com">Ran</a>
 * @Daate 2019/12/17 9:56
 **/
@Service
public class VersionParser {

    private static final Logger LOG = LoggerFactory.getLogger(VersionParser.class);

    public static final Map<String, Info> INFO = Maps.newHashMap();

    @Value(value = "${spring.application.name:#{null}}")
    private String app;

    @Autowired(required = false)
    Set<IVersion> ves;

    @Data
    public static class Info{
        private String name;
        private Map<String, Object> info = Maps.newHashMap();
        private List<Info> deps = Lists.newArrayList();

        public String getName() {
            return name;
        }

        public Map<String, Object> getInfo() {
            return info;
        }

        public List<Info> getDeps() {
            return deps;
        }

        public Info setName(String name) {
            this.name = name;
            return this;
        }

        public Info dep(Info info){
            this.deps.add(info);
            return this;
        }

        public Info desc(String key, Object val){
            this.info.put(key, val);
            return this;
        }
        public Info desc(Map<String, Object>  desc){
            this.info.putAll(desc);
            return this;
        }

        public com.uxsino.watcher.lib.bean.Value toVal(){
            List<com.uxsino.watcher.lib.bean.Value> props = Lists.newArrayList();
            this.getInfo().forEach((k,v)->{
                props.add(com.uxsino.watcher.lib.bean.Value.of(k, k, v));
            });
            if(this.getDeps() != null && !this.getDeps().isEmpty()){
                props.addAll(this.getDeps().stream().map(itm->itm.toVal()).collect(Collectors.toList()));
            }
            return com.uxsino.watcher.lib.bean.Value.of(this.getName(), this.getName(), props);
        }

    }


    public Info show(){
        List<Info> infos = Lists.newArrayList();
        try {
            new ClassPathResourceWalker("classpath*:/git.*.properties").forEach(url->{
                String srcName = Files.getNameWithoutExtension(url.getFile());
                String appnName= Strings.nullToEmpty(srcName).replace("git.","").replace(".properties", "");
                InputStream is = null;
                try {
                    is = url.openStream();
                    Info itm = new Info();
                    itm.setName(appnName);
                    itm.desc(parse(is));
                    infos.add(itm);
                } catch (IllegalArgumentException e) {
                    LOG.error("", "error loading indicator");
                } catch (IOException e) {
                    LOG.error("", "error reading indicator file", e);
                } finally {
                    if (is != null) {
                        try {
                            is.close();
                        } catch (IOException e) {
                        }
                    }
                }
            });
        }catch (Exception e){}

        Info info = infos.stream().filter(itm->Strings.nullToEmpty(itm.getName()).equals(app)).findFirst().orElse(new Info().setName(app));
        infos.stream().filter(itm->!Strings.nullToEmpty(itm.getName()).equals(app)).forEach(itm->{
            info.dep(itm);
        });

        return info;
    }


    private Map<String, Object> parse(InputStream in){
        Map<String, Object> pes = Maps.newHashMap();
        try {
            if (in == null) {
                return null;
            }
            Properties p = new Properties();
            p.load(in);
            p.forEach((k, v)->{
                pes.put(k.toString() ,v);
            });
        } catch (Exception e) {
            LOG.error("{}", e);
            return null;
        }
        return pes;
    }




}
